%%% -------------------------------------------------------------------
%%% Author  : vjache
%%% Description :
%%%
%%% Created : 21.09.2009
%%% -------------------------------------------------------------------
-module(erlioc_srv).

-behaviour(gen_server).
%% --------------------------------------------------------------------
%% Include files
%% --------------------------------------------------------------------
-include_lib("eunit/include/eunit.hrl").
-include("../include/erlioc.hrl").

%% --------------------------------------------------------------------
%% External exports
%% --------------------------------------------------------------------
-export([start_link/1]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

-define(SERVER,?MODULE).
-record(state, {}).

%% ====================================================================
%% External functions
%% ====================================================================


%% ====================================================================
%% Server functions
%% ====================================================================

%%--------------------------------------------------------------------
%% Function: start_link(Context) -> {ok,Pid} | ignore | {error,Error}
%% Description: Starts the Erlioc server
%%--------------------------------------------------------------------
start_link(Context) ->
    gen_server:start_link({local, ?SERVER}, ?MODULE, [Context], []).

%% --------------------------------------------------------------------
%% Function: init/1
%% Description: Initiates the server
%% Returns: {ok, State}          |
%%          {ok, State, Timeout} |
%%          ignore               |
%%          {stop, Reason}
%% --------------------------------------------------------------------
init(Context) when is_atom(Context) ->
	BeanList=Context:beans(),
	init_beans(BeanList),
	{ok, #state{}}.

init_beans(BeanList) ->
	BeanSpecByIdDict=lists:foldl(
			   fun(Bean,Acc)->
					   dict:store(Bean#bean.id, Bean, Acc)
			   end, dict:new(), BeanList),
	analyze_deps(BeanList,BeanSpecByIdDict),
	lists:foldl(fun(Bean,HD)->
					   {_,HD1}=init_bean(Bean#bean.id,BeanSpecByIdDict,HD),
					   HD1
			   end, dict:new(), BeanList).
init_bean({Context,Id},_BeanSpecByIdDict,HandleDict) ->
	{erlioc:get(Context, Id),HandleDict};
init_bean(Id,BeanSpecByIdDict,HandleDict) when is_atom(Id) ->
	#bean{id=Id,lifecycle=Lfc,create=CreFun,depends=Deps}=dict:fetch(Id, BeanSpecByIdDict),
	case dict:find(Id, HandleDict) of
		{ok,Handle} ->
			{Handle,HandleDict};
		error ->
			%% Init dependencies
			{Args,HandleDict1}=lists:foldl(
						  fun(DepId,{Args,HD}) ->
								  {H,HD1}=init_bean(DepId,BeanSpecByIdDict,HD),
								  {[H|Args],HD1}
						  end, {[],HandleDict}, Deps),
			Handle=apply(CreFun,lists:reverse(Args)),
			case Lfc of
				?SINGLETON ->
					{Handle,dict:store(Id, Handle, HandleDict1)};
				?PROTOTYPE ->
					{Handle,HandleDict1}
			end
	end.

analyze_deps(BeanList,BeanSpecByIdDict) ->
	G=digraph:new([acyclic,private]),
	ok.


%% --------------------------------------------------------------------
%% Function: handle_call/3
%% Description: Handling call messages
%% Returns: {reply, Reply, State}          |
%%          {reply, Reply, State, Timeout} |
%%          {noreply, State}               |
%%          {noreply, State, Timeout}      |
%%          {stop, Reason, Reply, State}   | (terminate/2 is called)
%%          {stop, Reason, State}            (terminate/2 is called)
%% --------------------------------------------------------------------
handle_call(Request, From, State) ->
    Reply = ok,
    {reply, Reply, State}.

%% --------------------------------------------------------------------
%% Function: handle_cast/2
%% Description: Handling cast messages
%% Returns: {noreply, State}          |
%%          {noreply, State, Timeout} |
%%          {stop, Reason, State}            (terminate/2 is called)
%% --------------------------------------------------------------------
handle_cast(Msg, State) ->
    {noreply, State}.

%% --------------------------------------------------------------------
%% Function: handle_info/2
%% Description: Handling all non call/cast messages
%% Returns: {noreply, State}          |
%%          {noreply, State, Timeout} |
%%          {stop, Reason, State}            (terminate/2 is called)
%% --------------------------------------------------------------------
handle_info(Info, State) ->
    {noreply, State}.

%% --------------------------------------------------------------------
%% Function: terminate/2
%% Description: Shutdown the server
%% Returns: any (ignored by gen_server)
%% --------------------------------------------------------------------
terminate(Reason, State) ->
    ok.

%% --------------------------------------------------------------------
%% Func: code_change/3
%% Purpose: Convert process state when code is changed
%% Returns: {ok, NewState}
%% --------------------------------------------------------------------
code_change(OldVsn, State, Extra) ->
    {ok, State}.

%% --------------------------------------------------------------------
%%% Internal functions
%% --------------------------------------------------------------------

